package cn.xjy.ddlc;

import cn.xjy.ddlc.context.MatchedTableItem;
import cn.xjy.ddlc.output.Displayer;
import cn.xjy.ddlc.context.MatchedColumnItem;
import cn.xjy.ddlc.context.MatchedDatabaseContext;
import cn.xjy.ddlc.context.MatchedDatabaseItem;
import cn.xjy.ddlc.context.MatchedIndexItem;
import cn.xjy.ddlc.context.MatchedViewItem;
import cn.xjy.ddlc.model.Column;
import cn.xjy.ddlc.model.Database;
import cn.xjy.ddlc.model.Index;
import cn.xjy.ddlc.model.Table;
import cn.xjy.ddlc.model.View;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Data
public class DatabaseComparator {
    
    Displayer displayer;
    
    public void compare(Database left, Database right) {
        MatchedDatabaseContext context = matchDatabase(left, right);
        
        for (MatchedTableItem tableItem : context.getTables()) {
            displayer.show(tableItem, true);
        }
        
        for (MatchedViewItem viewItem : context.getViews()) {
            displayer.show(viewItem, true);
        }
    }
    
    /**
     * 进行匹配 库索引和表
     */
    private MatchedDatabaseContext matchDatabase(Database left, Database right) {
        MatchedDatabaseContext context = new MatchedDatabaseContext();
        
        MatchedDatabaseItem databaseItem = new MatchedDatabaseItem();
        databaseItem.setLeft(left);
        databaseItem.setRight(right);
        context.setDatabase(databaseItem);
        java.util.List<MatchedTableItem> tableItems = new ArrayList<>();
        
        // 匹配表
        Set<Table> rightMatchedTables = new HashSet<>();
        for (Table leftTable : left.getTables()) {
            MatchedTableItem tableItem = null;
            for (Table rightTable : right.getTables()) {
                if (StringUtils.equalsIgnoreCase(leftTable.getName(), rightTable.getName())) {
                    tableItem = new MatchedTableItem();
                    tableItem.setLeft(leftTable);
                    tableItem.setRight(rightTable);
                    rightMatchedTables.add(rightTable);
                    break;
                }
            }
            if (tableItem == null) {
                tableItem = new MatchedTableItem();
                tableItem.setLeft(leftTable);
            }
            
            tableItems.add(tableItem);
            matchTable(tableItem);
        }
        for (Table rightTable : right.getTables()) {
            if (!rightMatchedTables.contains(rightTable)) {
                MatchedTableItem tableItem = new MatchedTableItem();
                tableItem.setRight(rightTable);
                tableItems.add(tableItem);
            }
        }
        context.setTables(tableItems);
        
        // 匹配 view
        List<MatchedViewItem> viewItems = new ArrayList<>();
        Set<View> rightMatchedViews = new HashSet<>();
        for (View leftView : left.getViews()) {
            MatchedViewItem viewItem = null;
            for (View rigthView : right.getViews()) {
                if (StringUtils.equalsIgnoreCase(leftView.getName(), rigthView.getName())) {
                    viewItem = new MatchedViewItem();
                    viewItem.setLeft(leftView);
                    viewItem.setRight(rigthView);
                    rightMatchedViews.add(rigthView);
                    break;
                }
            }
            if (viewItem == null) {
                viewItem = new MatchedViewItem();
                viewItem.setLeft(leftView);
            }
        }
        
        for (View rightView : right.getViews()) {
            if (!rightMatchedTables.contains(rightView)) {
                MatchedViewItem viewItem = new MatchedViewItem();
                viewItem.setRight(rightView);
                viewItems.add(viewItem);
            }
        }
        context.setViews(viewItems);
        return context;
    }
    
    /***
     * 匹配表格内的列和索引
     */
    private void matchTable(MatchedTableItem tableItem) {
        if (tableItem.getLeft() == null || tableItem.getRight() == null) {
            return;
        }
        
        // 匹配列
        List<MatchedColumnItem> columnItems = matcheColumns(tableItem.getLeft().getColumns(),
                tableItem.getRight().getColumns(), false);
        tableItem.setColumns(columnItems);
        
        // 匹配索引
        List<MatchedIndexItem> indexItems = matcheIndexs(tableItem.getLeft().getIndexs(),
                tableItem.getRight().getIndexs());
        tableItem.setIndexes(indexItems);
    }
    
    private List<MatchedIndexItem> matcheIndexs(List<Index> leftIndexs, List<Index> rigthIndexs) {
        List<MatchedIndexItem> indexItems = new ArrayList<>();
        if (leftIndexs == null) {
            leftIndexs = new ArrayList<>();
        }
        if (rigthIndexs == null) {
            rigthIndexs = new ArrayList<>();
        }
        
        List<Index> matchedRigthIndex = new ArrayList<>();
        for (Index leftIndex : leftIndexs) {
            MatchedIndexItem indexItem = null;
            for (Index rigthIndex : rigthIndexs) {
                if (StringUtils.equals(leftIndex.getName(), rigthIndex.getName())) {
                    indexItem = new MatchedIndexItem();
                    indexItem.setLeft(leftIndex);
                    indexItem.setRight(rigthIndex);
                    matchedRigthIndex.add(rigthIndex);
                }
            }
            if (indexItem == null) {
                indexItem = new MatchedIndexItem();
                indexItem.setLeft(leftIndex);
            }
            indexItems.add(indexItem);
        }
        for (Index rigthIndex : rigthIndexs) {
            if (!matchedRigthIndex.contains(rigthIndex)) {
                MatchedIndexItem indexItem = new MatchedIndexItem();
                indexItem.setRight(rigthIndex);
                indexItems.add(indexItem);
            }
        }
        
        return indexItems;
    }
    
    private List<MatchedColumnItem> matcheColumns(List<Column> leftColumns, List<Column> rightColumns,
                                                  boolean sequence) {
        if (!sequence) {
            return matchColumnsIgnoreSequence(leftColumns, rightColumns);
        }
        return matchColumnsRequireSequence(leftColumns, rightColumns);
    }
    
    /***
     * 匹配列 关心列顺序
     */
    private List<MatchedColumnItem> matchColumnsRequireSequence(List<Column> leftColumns, List<Column> rightColumns) {
        throw new RuntimeException("此方法未实现");
    }
    
    /***
     * 匹配列忽略顺序
     */
    private List<MatchedColumnItem> matchColumnsIgnoreSequence(List<Column> leftColumns, List<Column> rightColumns) {
        List<MatchedColumnItem> indexItems = new ArrayList<>();
        if (leftColumns == null) {
            leftColumns = new ArrayList<>();
        }
        if (rightColumns == null) {
            rightColumns = new ArrayList<>();
        }
        List<Column> matchedRightColumn = new ArrayList<>();
        for (Column leftColumn : leftColumns) {
            MatchedColumnItem columnItem = null;
            for (Column rightColum : rightColumns) {
                if (StringUtils.equals(leftColumn.getName(), rightColum.getName())) {
                    columnItem = new MatchedColumnItem();
                    columnItem.setLeft(leftColumn);
                    columnItem.setRight(rightColum);
                    matchedRightColumn.add(rightColum);
                }
            }
            if (columnItem == null) {
                columnItem = new MatchedColumnItem();
                columnItem.setLeft(leftColumn);
            }
            indexItems.add(columnItem);
        }
        for (Column rigthColumn : rightColumns) {
            if (!matchedRightColumn.contains(rigthColumn)) {
                MatchedColumnItem indexItem = new MatchedColumnItem();
                indexItem.setRight(rigthColumn);
                indexItems.add(indexItem);
            }
        }
        return indexItems;
    }
}
